import json

from django.shortcuts import render
from django.views import View
from django import http
from meiduo_mall.libs.captcha.captcha import captcha
from django_redis import get_redis_connection
import random
from meiduo_mall.libs.yuntongxun.sms import CCP
from meiduo_mall.utils.response_code import RET
from oauth.utils import encode_openid, decode_openid
from users.models import User
from verifications import constants

# 1,图片验证码
class ImageCodeView(View):
    def get(self, request, image_code_id):
        # 1,生成图片验证码
        name, text, image_data = captcha.generate_captcha()

        # 2,保存图片验证码到redis中
        redis_conn = get_redis_connection("code")
        # 参数1: 保存到redis键,  参数2: 有效期,  参数3: 值
        redis_conn.setex("img_code_%s" % image_code_id, constants.REDIS_IMAGE_CODE_EXPIRES, text)

        # 3,返回图片验证码
        return http.HttpResponse(image_data, content_type="image/png")


# 2,发送短信验证码
class SmsCodeView(View):
    def get(self, request, mobile):
        # 1,获取参数
        image_code = request.GET.get("image_code")
        image_code_id = request.GET.get("image_code_id")

        # 2,校验参数
        # 2,1 为空校验
        if not all([image_code, image_code_id]):
            return http.JsonResponse({"code": RET.PARAMERR, "errmsg": "参数不完整"})

        # 2,2 获取redis中的图片验证码,校验为空
        redis_conn = get_redis_connection("code")
        pipeline = redis_conn.pipeline()  # 开启管道(事务)
        redis_image_code = redis_conn.get("img_code_%s" % image_code_id)

        # 判断是否过期
        if not redis_image_code:
            return http.JsonResponse({"code": RET.NODATA, "errmsg": "图片验证码过期"})

        # 删除redis验证码
        pipeline.delete("img_code_%s" % image_code_id)

        # 2,3 图片验证码正确性
        if image_code.lower() != redis_image_code.decode().lower():
            return http.JsonResponse({"code": RET.DATAERR, "errmsg": "图片验证码错误"})

        # 获取短信验证码标记
        send_flag = redis_conn.get("send_flag_%s" % mobile)
        if send_flag:
            return http.JsonResponse({"code": RET.DATAERR, "errmsg": "短信发送频繁"}, status=400)

        # 3,发送短信,并判断是否发送成功
        sms_code = "%06d" % random.randint(0, 999999)
        print("sms_code = %s" % sms_code)
        # ccp = CCP()
        # result = ccp.send_template_sms(mobile, [sms_code, constants.REDIS_SMS_CODE_EXPIRES/60], 1)
        #
        # #判断是否发送成功
        # if result == -1:
        #     return http.JsonResponse({"code": RET.THIRDERR, "errmsg": "短信发送失败"})

        # 使用celery发送短信
        from celery_tasks.sms.tasks import send_sms_code
        send_sms_code.delay(mobile, sms_code, constants.REDIS_SMS_CODE_EXPIRES / 60)

        # 测试短信发送
        # import time
        # time.sleep(10)

        # 保存短信验证到redis
        pipeline.setex("sms_code_%s" % mobile, constants.REDIS_SMS_CODE_EXPIRES, sms_code)
        pipeline.setex("send_flag_%s" % mobile, 60, 0)

        pipeline.execute()  # 提交管道(事务)

        # 4,返回响应
        return http.JsonResponse({"code": RET.OK, "errmsg": "ok"})


# 3.找回密码界面
class FPWView(View):
    def get(self, request):
        return render(request, 'find_password.html')


# 3. 找回密码,第一次点击下一步根据账号和图片验证码,请求返回修改第二步的页面
class StepOneView(View):
    def get(self, request, username):
        # 1. 获取传递过来的手机号和图片验证码,前端中使用text表示验证码内容
        image_code_id = request.GET.get('image_code_id')
        image_code = request.GET.get("text")

        # 2. 为空校验
        if not all([image_code_id, image_code, username]):
            return http.JsonResponse({"code": RET.PARAMERR, "errmsg": "请输入完整的参数"})

        # 3.1 先连接redis数据库,判断图片验证码是否失效,再判断输入是否正确
        # 数据库查询出来
        redis_conn1 = get_redis_connection("code")
        redis_image_code = redis_conn1.get("img_code_%s" % image_code_id)
        if not redis_image_code:
            return http.JsonResponse({"errmsg": "图片验证码输入错误", "code": RET.PARAMERR})  # 返回图片验证码失效信息
        # 图片验证码没有过期,立即删除,每张图片只能使用一次
        redis_conn1.delete("img_code_%s" % image_code_id)

        if redis_image_code.decode().lower() != image_code.lower():
            # return http.JsonResponse({"errmsg": "图片验证码输入错误", "code": RET.PARAMERR})  # 图片验证码错误
            return http.JsonResponse({}, status=400)  # 图片验证码错误

        # 3.2 根据用户名查询用户数据库的手机号,返回到前端显示
        # 如果有异常则报错, 捕获异常
        try:
            user_object = User.objects.get(username=username)
        except Exception as e:
            print("错误的用户名")
            return http.JsonResponse({}, status=404)  # 返回用户或者手机号不存在信息
        # 3.3 根据用户对象获取手机号用来返回前端；　构造access_token,加密手机号数据来设置有效期
        mobile = user_object.mobile
        access_token = encode_openid(mobile)
        # 4.0 携带手机号和加密后的用户名返回到前端
        context = {
            "mobile": mobile,
            "access_token": access_token
               }
        return http.JsonResponse(context)


# 4. 找回密码,点击获取短信验证码
class StepTwoSendCodeView(View):
    def get(self, request):
        # 1. 获取参数access_token，解密得到手机号
        access_token = request.GET.get("access_token")
        mobile = decode_openid(access_token)
        if mobile is None:
            return http.JsonResponse({"error_sms_code_message": "操作超时,请重新操作"}, status=400)
        # 2. 连接数据库,查询短信发送频繁标志是否有效
        redis_conn2 = get_redis_connection("code")
        send_flag = redis_conn2.get("send_flag_%s" % mobile)
        print(send_flag)
        if send_flag:
            return http.JsonResponse({"error_sms_code_message": "短信发送频繁,请稍后再发"}, status=401)
        # 3. 随机产生短信验证码,并使用celery任务进行短信发送
        sms_code_two = "%06d" % random.randint(0, 999999)
        from celery_tasks.sms.tasks import send_sms_code
        print("第二次发送手机验证码之前输出手机号", mobile)
        print("第二次发送手机验证码之前输出验证码", sms_code_two)
        send_sms_code.delay(mobile, sms_code_two, constants.REDIS_SMS_CODE_EXPIRES / 60)
        # 把短信发送标志存入数据库，下次发送短信前先检查该标志
        redis_conn2.setex("send_flag_%s" % mobile, 60, 'True')
        return http.JsonResponse({"send_success_flag": "true", "send_success_msg": "短信发送成功"})


# 5. 找回密码,点击提交短信验证码信息
class StepTwoFormView(View):
    def post(self, request, username):  # url中正则匹配用户名,传递到后端
        # 1. 获取前端传递来验证码参数
        dict_data = json.loads(request.body.decode())  # 获取不到值!前端虽为post请求, 但参数不在请求体之中.
        sms_code = request.GET.get("sms_code")
        if sms_code is None:
            return http.JsonResponse({}, status=400)  # 验证码错误信息提醒
        # 2. 根据传递来的用户名参数获取用户对象,验证前端传递过来的用户是否存在——虽然第一次已经验证过,为了安全需再验证
        try:
            user = User.objects.get(username=username)
        except Exception as e:
            return http.JsonResponse({}, status=404)  # 手机号不存在
        # 3.加密用户名传返回到前端, 构造返回数据
        access_token = encode_openid(username)
        user_id = user.id
        context = {
            "access_token": access_token,
            "user_id": user.id
        }
        return http.JsonResponse(context)


# 6. 找回密码第三步，表单数据使用axio发送过来,而不是表单的method属性——所以使用body获取数据.
class StepThreeFormView(View):
    def post(self, request, user_id):
        # 1. 获取前端提交的表单数据,
        dict_data = json.loads(request.body.decode())
        password = dict_data.get("password")
        password2 = dict_data.get("password2")
        access_token = dict_data.get("access_token")
        # 2. 验证access_token是否有效,若无效则说明token过期——操作超时,使用message变量
        if not all([password, password2, access_token]):
            return http.JsonResponse({"message": "参数不全"})
        if access_token is None:
            return http.JsonResponse({"message": "操作超时,获取数据失败"})
        # 3. 验证两次密码是否一致。　前端验证过,但如果强行提交则需要这里去验。
        print("打印密码类型", type(password))
        if password.lower() != password2.lower():
            return http.JsonResponse({"message": "两次密码输入不一致"})

        # 4. 解密access_token,获取用户对象,修改该对象的用户密码
        username = decode_openid(access_token)
        try:  # 再次验证用户名的合法性
            user = User.objects.get(username=username)
        except Exception as e:
            return http.JsonResponse({"message": "手机号或用户不存在"})
        # 修改密码
        user.password = password
        print("打印新密码", user.password)
        return http.JsonResponse({"message": "ok"})
